﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using l1cs.server.server.types;

namespace l1cs.server.model.map
{
    abstract public class L1Map
    {
        private static L1NullMap _nullMap = new L1NullMap();

        protected L1Map() { }

        /// <summary>
        /// このマップのマップIDを返す。
        /// </summary>
        /// <returns>マップID</returns>
        public abstract int getId();

        public abstract int getX();

        public abstract int getY();

        public abstract int getWidth();

        public abstract int getHeight();

        /// <summary>
        /// 指定された座標の値を返す。
        /// </summary>
        /// <param name="x">座標のX値</param>
        /// <param name="y">座標のY値</param>
        /// <returns>指定された座標の値</returns>
        /// <remarks>
        /// 推奨されていません。このメソッドは、既存コードとの互換性の為に提供されています。
        /// L1Mapの利用者は通常、マップにどのような値が格納されているかを知る必要はありません。
        /// また、格納されている値に依存するようなコードを書くべきではありません。 デバッグ等の特殊な場合に限り、
        /// このメソッドを利用できます。
        /// </remarks>
        public abstract int getTile( int x, int y );

        /// <summary>
        /// 指定された座標の値を返す。
        /// </summary>
        /// <param name="x">座標のX値</param>
        /// <param name="y">座標のY値</param>
        /// <returns>指定された座標の値</returns>
        /// <remarks>
        /// 推奨されていません。このメソッドは、既存コードとの互換性の為に提供されています。
        /// L1Mapの利用者は通常、マップにどのような値が格納されているかを知る必要はありません。
        /// また、格納されている値に依存するようなコードを書くべきではありません。 
        /// デバッグ等の特殊な場合に限り、このメソッドを利用できます。
        /// </remarks>
        public abstract int getOriginalTile( int x, int y );

        /// <summary>
        /// 指定された座標がマップの範囲内であるかを返す。
        /// </summary>
        /// <param name="pt">座標を保持するPointオブジェクトX値</param>
        /// <param name="y">座標のY値</param>
        /// <returns>範囲内であればtrue</returns>
        public abstract bool isInMap( Point pt );

        /// <summary>
        /// 指定された座標がマップの範囲内であるかを返す。
        /// </summary>
        /// <param name="x">座標のX値</param>
        /// <param name="y">座標のY値</param>
        /// <returns>範囲内であればtrue</returns>
        public abstract bool isInMap( int x, int y );

        /// <summary>
        /// 指定された座標が通行可能であるかを返す。
        /// </summary>
        /// <param name="pt">座標を保持するPointオブジェクト</param>
        /// <returns>通行可能であればtrue</returns>
        public abstract bool isPassable( Point pt );

        /// <summary>
        /// 指定された座標が通行可能であるかを返す。
        /// </summary>
        /// <param name="x">座標のX値</param>
        /// <param name="y">座標のY値</param>
        /// <returns>通行可能であればtrue</returns>
        public abstract bool isPassable( int x, int y );

        /// <summary>
        /// 指定された座標のheading方向が通行可能であるかを返す。
        /// </summary>
        /// <param name="pt"></param>
        /// <param name="heading"></param>
        /// <returns>通行可能であればtrue</returns>
        public abstract bool isPassable( Point pt, int heading );

        /// <summary>
        /// 指定された座標のheading方向が通行可能であるかを返す。
        /// </summary>
        /// <param name="x">座標のX値</param>
        /// <param name="y">座標のY値</param>
        /// <param name="heading"></param>
        /// <returns>通行可能であればtrue</returns>
        public abstract bool isPassable( int x, int y, int heading );

        /// <summary>
        /// 指定された座標の通行可能、不能を設定する。
        /// </summary>
        /// <param name="pt">座標を保持するPointオブジェクト</param>
        /// <param name="isPassable">通行可能であればtrue</param>
        public abstract void setPassable( Point pt, bool isPassable );

        /// <summary>
        /// 指定された座標の通行可能、不能を設定する。
        /// </summary>
        /// <param name="x">座標のX値</param>
        /// <param name="y">座標のY値</param>
        /// <param name="isPassable">通行可能であればtrue</param>
        public abstract void setPassable( int x, int y, bool isPassable );

        /// <summary>
        /// 指定された座標がセーフティーゾーンであるかを返す。
        /// </summary>
        /// <param name="pt">座標を保持するPointオブジェクト</param>
        /// <returns>セーフティーゾーンであればtrue</returns>
        public abstract bool isSafetyZone( Point pt );

        /// <summary>
        /// 指定された座標がセーフティーゾーンであるかを返す。
        /// </summary>
        /// <param name="x">座標のX値</param>
        /// <param name="y">座標のY値</param>
        /// <returns>セーフティーゾーンであればtrue</returns>
        public abstract bool isSafetyZone( int x, int y );

        /// <summary>
        /// 指定された座標がコンバットゾーンであるかを返す。
        /// </summary>
        /// <param name="pt">座標を保持するPointオブジェクト</param>
        /// <returns>コンバットゾーンであればtrue</returns>
        public abstract bool isCombatZone( Point pt );

        /// <summary>
        /// 指定された座標がコンバットゾーンであるかを返す。
        /// </summary>
        /// <param name="x">座標のX値</param>
        /// <param name="y">座標のY値</param>
        /// <returns>コンバットゾーンであればtrue</returns>
        public abstract bool isCombatZone( int x, int y );

        /// <summary>
        /// 指定された座標がノーマルゾーンであるかを返す。
        /// </summary>
        /// <param name="pt">座標を保持するPointオブジェクト</param>
        /// <returns>ノーマルゾーンであればtrue</returns>
        public abstract bool isNormalZone( Point pt );

        /// <summary>
        /// 指定された座標がノーマルゾーンであるかを返す。
        /// </summary>
        /// <param name="x">座標のX値</param>
        /// <param name="y">座標のY値</param>
        /// <returns>ノーマルゾーンであればtrue</returns>
        public abstract bool isNormalZone( int x, int y );

        /// <summary>
        /// 指定された座標が矢や魔法を通すかを返す。
        /// </summary>
        /// <param name="pt">座標を保持するPointオブジェクト</param>
        /// <returns>矢や魔法を通す場合、true</returns>
        public abstract bool isArrowPassable( Point pt );

        /// <summary>
        /// 指定された座標が矢や魔法を通すかを返す。
        /// </summary>
        /// <param name="x">座標のX値</param>
        /// <param name="y">座標のY値</param>
        /// <returns></returns>
        public abstract bool isArrowPassable( int x, int y );

        /// <summary>
        /// 指定された座標のheading方向が矢や魔法を通すかを返す。
        /// </summary>
        /// <param name="pt">座標を保持するPointオブジェクト</param>
        /// <param name="heading">方向</param>
        /// <returns>矢や魔法を通す場合、true</returns>
        public abstract bool isArrowPassable( Point pt, int heading );

        /// <summary>
        /// 指定された座標のheading方向が矢や魔法を通すかを返す。
        /// </summary>
        /// <param name="x">座標のX値</param>
        /// <param name="y">座標のY値</param>
        /// <param name="heading">方向</param>
        /// <returns>矢や魔法を通す場合、true</returns>
        public abstract bool isArrowPassable( int x, int y, int heading );

        /// <summary>
        /// このマップが、水中マップであるかを返す。
        /// </summary>
        /// <returns>水中であれば、true</returns>
        public abstract bool isUnderwater();

        /// <summary>
        /// このマップが、ブックマーク可能であるかを返す。
        /// </summary>
        /// <returns>ブックマーク可能であれば、true</returns>
        public abstract bool isMarkable();

        /// <summary>
        /// このマップが、ランダムテレポート可能であるかを返す。
        /// </summary>
        /// <returns>ランダムテレポート可能であれば、true</returns>
        public abstract bool isTeleportable();

        /// <summary>
        /// このマップが、MAPを超えたテレポート可能であるかを返す。
        /// </summary>
        /// <returns>テレポート可能であれば、true</returns>
        public abstract bool isEscapable();

        /// <summary>
        /// このマップが、復活可能であるかを返す。
        /// </summary>
        /// <returns>復活可能であれば、true</returns>
        public abstract bool isUseResurrection();

        /// <summary>
        /// このマップが、パインワンド使用可能であるかを返す。
        /// </summary>
        /// <returns>パインワンド使用可能であれば、true</returns>
        public abstract bool isUsePainwand();

        /// <summary>
        /// このマップが、デスペナルティがあるかを返す。
        /// </summary>
        /// <returns>デスペナルティがあれば、true</returns>
        public abstract bool isEnabledDeathPenalty();

        /// <summary>
        /// このマップが、ペット・サモンを連れて行けるかを返す。
        /// </summary>
        /// <returns>ペット・サモンを連れて行けるならばtrue</returns>
        public abstract bool isTakePets();

        /// <summary>
        /// このマップが、ペット・サモンを呼び出せるかを返す。
        /// </summary>
        /// <returns>ペット・サモンを呼び出せるならばtrue</returns>
        public abstract bool isRecallPets();

        /// <summary>
        /// このマップが、アイテムを使用できるかを返す。
        /// </summary>
        /// <returns>アイテムを使用できるならばtrue</returns>
        public abstract bool isUsableItem();

        /// <summary>
        /// このマップが、スキルを使用できるかを返す。
        /// </summary>
        /// <returns>スキルを使用できるならばtrue</returns>
        public abstract bool isUsableSkill();

        /// <summary>
        /// 指定された座標が釣りゾーンであるかを返す。
        /// </summary>
        /// <param name="x">座標のX値</param>
        /// <param name="y">座標のY値</param>
        /// <returns>釣りゾーンであればtrue</returns>
        public abstract bool isFishingZone( int x, int y );

        /// <summary>
        /// 指定された座標にドアが存在するかを返す。
        /// </summary>
        /// <param name="x">座標のX値</param>
        /// <param name="y">座標のY値</param>
        /// <returns>ドアがあればtrue</returns>
        public abstract bool isExistDoor( int x, int y );

        public static L1Map newNull()
        {
            return _nullMap;
        }

        /// <summary>
        /// 指定されたptのタイルの文字列表現を返す。
        /// </summary>
        /// <param name="pt"></param>
        /// <returns></returns>
        public abstract String toString( Point pt );

        /// <summary>
        /// このマップがnullであるかを返す。
        /// </summary>
        /// <returns>nullであれば、true</returns>
        public bool isNull()
        {
            return false;
        }
    }
}
